home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech's Sprocket™ / SprocketGX / Lib / Window.cp < prev   
Encoding:
Text File  |  1994-10-18  |  21.4 KB  |  795 lines  |  [TEXT/MMCC]

  1. /*
  2.     File:        Window.cp
  3.  
  4.     Contains:    Implementation of TWindow, a base class which provides a
  5.                 framework for building way-cool windows which even John
  6.                 Sullivan would be happy with. Floating windows and “smart
  7.                 zooming” algorithms are based on code samples provided by
  8.                 Dean Yu. Tim Craycroft, the guy making the window manager
  9.                 do all this work for you has also been a great help.
  10.                 
  11.     Written by: Dave Falkenburg
  12.  
  13.     Copyright:    © 1993-94 by Dave Falkenburg, all rights reserved.
  14.  
  15.     Change History (most recent first):
  16.     
  17.          <2>     8/27/94    DRF        In TWindow::Close, call window’s (de)Activate method before
  18.                                     closing so that menus can be properly updated.
  19.     
  20.     To Do:        Make sure invisible windows can be created & managed
  21.                 Handle modal windows as another class of windows
  22.                 Fix activate bugs when showing and hiding windows
  23.                 Window positioning methods (getters and setters)
  24.                 Display Manager support
  25.                 Changes to support AEObject model
  26.  */
  27.  
  28. #include <Types.h>
  29. #include <Windows.h>
  30. #include <Errors.h>
  31. #include <Script.h>        //    for GetMBarHeight()
  32. #include <LowMem.h>        //    for LMGetWindowList()
  33.  
  34. #include "AppLib.h"
  35. #include "Window.h"
  36.  
  37. const short            kFloatingWindowKind        = 1000;
  38. const short            kNormalWindowKind        = 1001;
  39. const WindowPtr     kNoFloatingWindows        = (WindowPtr) -1;
  40.  
  41. const short            kScreenEdgeSlop            = 4;
  42. const short            kSpaceForFinderIcons    = 64;
  43. const short            kMinimumTitleBarHeight    = 21;
  44. const short            kMinimumWindowSize        = 32;
  45.  
  46. static void            HiliteShowHideFloatingWindows(Boolean hiliting,Boolean hiding);
  47.  
  48. static void            FindScreenRectWithLargestPartOfWindow(WindowPtr aWindow,Rect *theBestScreenRect, GDHandle * theBestDevice);
  49. static pascal void    CalculateWindowAreaOnDevice(short depth,short deviceFlags,GDHandle targetDevice,long userData);
  50.  
  51. struct    CalcWindowAreaDeviceLoopUserData
  52. {
  53.     GDHandle    fScreenWithLargestPartOfWindow;
  54.     long        fLargestArea;
  55.     Rect        fWindowBounds;
  56. };
  57.  
  58. TWindow::TWindow()
  59.  : fWindow(nil)
  60. {
  61. }
  62.  
  63. TWindow::~TWindow()
  64. {
  65. }
  66.  
  67. void TWindow::CreateWindow(WindowType typeOfWindowToCreate /* = kNormalWindow */)
  68. {
  69.     WindowPtr    behindWindow,oldFrontMostWindow;
  70.     
  71.     if (typeOfWindowToCreate == kModalWindow)
  72.     {
  73.         DebugStr("\pModal windows aren’t supported yet");
  74.         fWindowType = kFloatingWindow;
  75.         return;
  76.     }
  77.     else if (typeOfWindowToCreate == kFloatingWindow)
  78.     {
  79.         behindWindow = (WindowPtr) -1;
  80.         oldFrontMostWindow = FrontWindow();
  81.  
  82.         fWindowType = kFloatingWindow;
  83.     }
  84.     else if (typeOfWindowToCreate == kNormalWindow)
  85.     {
  86.         behindWindow = LastFloatingWindow();
  87.  
  88.         fWindowType = kNormalWindow;
  89.         
  90.         if (behindWindow == kNoFloatingWindows)
  91.             oldFrontMostWindow = nil;
  92.         else
  93.             oldFrontMostWindow = (WindowPtr) ((WindowPeek) behindWindow)->nextWindow;
  94.     }
  95.  
  96.     fWindow = this->MakeNewWindow(behindWindow);
  97.  
  98.     fIsVisible = ((WindowPeek) fWindow)->visible;
  99.  
  100.     if (fWindow)
  101.     {
  102.         ShowWindow(fWindow);
  103.         SetWRefCon(fWindow,(long) this);
  104.  
  105.         if (typeOfWindowToCreate == kModalWindow)
  106.         {
  107.             DebugStr("\pCan’t create Modal windows yet");
  108.         }
  109.         else if (typeOfWindowToCreate == kFloatingWindow)
  110.         {
  111.             ((WindowPeek) fWindow)->windowKind = kFloatingWindowKind;
  112.             
  113.             //    make sure the other window stays hilited
  114.             if (oldFrontMostWindow)
  115.                 HiliteAndActivateWindow(oldFrontMostWindow,true);
  116.         }
  117.         else if (typeOfWindowToCreate == kNormalWindow)
  118.         {
  119.             ((WindowPeek) fWindow)->windowKind = kNormalWindowKind;
  120.  
  121.             //    unhighlight the old front window
  122.             if (oldFrontMostWindow)
  123.                 HiliteAndActivateWindow(oldFrontMostWindow,false);
  124.  
  125.             //    hilite the new window…
  126.             HiliteAndActivateWindow(fWindow,true);
  127.         }
  128.     }
  129. }
  130.  
  131. void TWindow::SetupMenus(void)
  132. {
  133.     if (fWindowType != kFloatingWindow)
  134.     {
  135.         EnableMenuItem(mFile, iClose, true);
  136.         EnableMenuItem(mWindows, iTileWindows, true);
  137.         EnableMenuItem(mWindows, iStackWindows, true);
  138.     }
  139. }
  140.  
  141. void TWindow::AdjustCursor(EventRecord * /* anEvent */)
  142. {
  143. }
  144.  
  145. void TWindow::Idle(EventRecord * /* anEvent */)
  146. {
  147. }
  148.     
  149. void TWindow::Activate(Boolean /* activating */)
  150. {
  151. }
  152.     
  153. void TWindow::Draw(void)
  154. {
  155. }
  156.     
  157. void TWindow::Click(EventRecord * /* anEvent */)
  158. {
  159. }
  160.     
  161. void TWindow::KeyDown(EventRecord * /* anEvent */)
  162. {
  163. }
  164.  
  165. void TWindow::Select(void)
  166. {
  167.     WindowPtr    currentFrontWindow;
  168.     
  169.     if (fWindowType == kFloatingWindow)
  170.         currentFrontWindow = FrontWindow();
  171.     else if (fWindowType == kNormalWindow)
  172.         currentFrontWindow = FrontNonFloatingWindow();
  173.     else
  174.     {
  175.     }
  176.  
  177.     if (currentFrontWindow != fWindow)
  178.     {
  179.         if (fWindowType == kFloatingWindow)
  180.             BringToFront(fWindow);
  181.         else
  182.         {
  183.             WindowPtr    lastFloater = LastFloatingWindow();
  184.  
  185.             //    If there are no floating windows,
  186.             //    just call SelectWindow like the good ol’ days
  187.  
  188.             if (lastFloater == kNoFloatingWindows)
  189.                 SelectWindow(fWindow);
  190.             else
  191.             {
  192.                 // Deactivate the window currently in front.
  193.  
  194.                 HiliteAndActivateWindow(currentFrontWindow,false);
  195.     
  196.                 // Bring it behind the last floating window and activate it.
  197.                 // Note that Inside Mac 1 states that you need to call PaintOne() and CalcVis() on a
  198.                 // window if you are using SendBehind() to bring it closer to the front.  With System 7,
  199.                 // this is no longer necessary.
  200.  
  201.                 SendBehind(fWindow,lastFloater);
  202.                 HiliteAndActivateWindow(fWindow,true);
  203.             }
  204.         }
  205.     }
  206. }
  207.  
  208. void TWindow::Drag(Point startPoint)
  209. {
  210.     Boolean        commandKeyDown = false;
  211.     
  212.     if (WaitMouseUp())        //    de-bounce?
  213.     {
  214.         long        dragResult;
  215.         {
  216.             // Set up the Window Manager port.
  217.             CSavePort  aSavePort(gWindowManagerPort);
  218.             WindowPeek    windowAsWindowPeek = (WindowPeek) fWindow;
  219.             KeyMap        theKeyMap;
  220.         
  221.             SetClip(GetGrayRgn());
  222.     
  223.             // Check to see if the command key is down.
  224.         
  225.             GetKeys(theKeyMap);
  226.             commandKeyDown = ((theKeyMap[1] & 0x8000) != 0);
  227.             
  228.             if (commandKeyDown)
  229.             {
  230.                 //    We’re not going to change window ordering,
  231.                 //    so make sure that we don’t drag in front of
  232.                 //    other windows which may be in front of ours.
  233.     
  234.                 ClipAbove(windowAsWindowPeek);
  235.             }
  236.             else if (fWindowType != kFloatingWindow)
  237.             {
  238.                 //    We’re dragging a normal window, so make sure
  239.                 //    that we don’t drag in front of any floating
  240.                 //    windows.
  241.     
  242.                 ClipAbove((WindowPeek) FrontNonFloatingWindow());
  243.             }
  244.             
  245.             //    Drag an outline of the window around the desktop.
  246.             //    NOTE: DragGrayRgn destroys the region passed in, so make a copy
  247.             {
  248.                 RgnHandle    draggingRegion = NewRgn();
  249.                 CopyRgn(windowAsWindowPeek->strucRgn,draggingRegion);
  250.                 dragResult = DragGrayRgn(draggingRegion, startPoint, &gDeskRectangle, &gDeskRectangle, noConstraint, nil);
  251.                 DisposeRgn(draggingRegion);
  252.             }
  253.         }    //    Get back to old port
  254.     
  255.         if ((dragResult != 0) && (dragResult != 0x80008000))
  256.         {
  257.             this->Nudge((dragResult & 0xFFFF),(dragResult >> 16));
  258.         }
  259.     }
  260.  
  261.     if (!commandKeyDown)
  262.         Select();
  263. }
  264.  
  265. void TWindow::Nudge(short theHorizontalDistance, short theVerticalDistance)
  266. {
  267.     WindowPeek    windowAsWindowPeek = (WindowPeek) fWindow;
  268.     short        aNewHorizontalPosition;
  269.     short        aNewVerticalPosition;
  270.     
  271.     aNewHorizontalPosition = (short) (*windowAsWindowPeek->contRgn)->rgnBBox.left + theHorizontalDistance;
  272.     aNewVerticalPosition = (short) (*windowAsWindowPeek->contRgn)->rgnBBox.top + theVerticalDistance;
  273.  
  274.     MoveWindow(fWindow, aNewHorizontalPosition, aNewVerticalPosition, false);
  275. }
  276.  
  277. void TWindow::Grow(Point startPoint)
  278. {
  279.     CSavePort  aSavePort(nil);
  280.     long        aNewSize;
  281.     Rect        aResizeLimits;
  282.     Rect        aOldWindowRect = fWindow->portRect;
  283.         
  284.     GetWindowSizeLimits(&aResizeLimits);
  285.     aNewSize = GrowWindow(fWindow,startPoint,&aResizeLimits);
  286.     if (aNewSize)
  287.     {
  288.         SizeWindow(fWindow,(short) aNewSize,(short) (aNewSize >> 16),true);
  289.         SetPort(fWindow);
  290.         this->AdjustForNewWindowSize(&aOldWindowRect, &fWindow->portRect);
  291.     }
  292. }
  293.  
  294. void TWindow::Zoom(short zoomState)
  295. {
  296.     CSavePort  aSavePort(gWindowManagerPort);
  297.     FontInfo    systemFontInfo;
  298.     short        titleBarHeight;
  299.     Rect        bestScreenRect,perfectWindowRect,scratchRect;
  300.     short        amountOffscreen;
  301.     WindowPeek    windowAsWindowPeek = (WindowPeek) fWindow;
  302.     GDHandle    bestDevice;
  303.     
  304.     //    Figure out the height of the title bar so we can properly position
  305.     //    a window. The algorithm is stolen from the System 7.x 'WDEF' (0)
  306.     //
  307.     //    This probably isn’t the best thing to do: A better way might be 
  308.     //    to diff the structure and content region rectangles?
  309.  
  310.     GetFontInfo(&systemFontInfo);
  311.     titleBarHeight = (short) (systemFontInfo.ascent + systemFontInfo.descent + 4);
  312.     if ((titleBarHeight % 2) == 1)
  313.         titleBarHeight--;
  314.     if (titleBarHeight < kMinimumTitleBarHeight)
  315.         titleBarHeight = kMinimumTitleBarHeight;
  316.  
  317.     //    Only do the voodoo magic if we are really “zooming” the window.
  318.  
  319.     if (zoomState == inZoomOut)
  320.     {
  321.         FindScreenRectWithLargestPartOfWindow(fWindow,&bestScreenRect,&bestDevice);
  322.         bestScreenRect.top += titleBarHeight;
  323.  
  324.         this->GetPerfectWindowSize(&perfectWindowRect);
  325.         OffsetRect(&perfectWindowRect,-perfectWindowRect.left,-perfectWindowRect.top);
  326.  
  327.         //    Take the zero-pined perfect window size and move it to
  328.         //    the top left of the    window’s content region.
  329.  
  330.         OffsetRect(&perfectWindowRect,(**windowAsWindowPeek->contRgn).rgnBBox.left,
  331.                                       (**windowAsWindowPeek->contRgn).rgnBBox.top);
  332.  
  333.                 //    Does perfectWindowRect fit completely on the best screen?
  334.         
  335.         SectRect(&perfectWindowRect, &bestScreenRect, &scratchRect);
  336.         if (!EqualRect(&perfectWindowRect, &scratchRect))
  337.         {
  338.             //    SectRect sez perfectWindowRect doesn’t completely fit
  339.             //    on the screen, so bump the window so that more of it fits.
  340.  
  341.             //    Make sure that the left edge of perfectWindowRect is forced
  342.             //    onto the best screen.  This is in case we are bumping
  343.             //    the window to the right.
  344.  
  345.             amountOffscreen = bestScreenRect.left - perfectWindowRect.left;
  346.             if (amountOffscreen > 0)
  347.             {
  348.                 perfectWindowRect.left += amountOffscreen;
  349.                 perfectWindowRect.right += amountOffscreen;
  350.             }
  351.  
  352.             //    Make sure that the left edge of perfectWindowRect is forced
  353.             //    onto the best screen.  This is in case we are bumping
  354.             //    the window downward to a new screen.
  355.     
  356.             amountOffscreen = bestScreenRect.top - perfectWindowRect.top;
  357.             if (amountOffscreen > 0)
  358.             {
  359.                 perfectWindowRect.top += amountOffscreen;
  360.                 perfectWindowRect.bottom += amountOffscreen;
  361.             }
  362.  
  363.             //    If right edge of window falls off the screen,
  364.             //        Move window to the left until the right edge IS on the screen
  365.             //        OR the left edge is at bestScreenRect.left
  366.  
  367.             amountOffscreen = perfectWindowRect.right - bestScreenRect.right;
  368.             if (amountOffscreen > 0)
  369.             {
  370.                 //    Are we going to push the left edge offscreen? If so, change the
  371.                 //    offset so we move the window all the way over to the left.
  372.                 
  373.                 if ((perfectWindowRect.left - amountOffscreen) < bestScreenRect.left)
  374.                     amountOffscreen = perfectWindowRect.left - bestScreenRect.left;
  375.  
  376.                 perfectWindowRect.left -= amountOffscreen;
  377.                 perfectWindowRect.right -= amountOffscreen;
  378.             }
  379.  
  380.             //    If bottom edge of window falls off the screen,
  381.             //        Move window to up until the bottom edge IS on the screen
  382.             //        OR the top edge is at bestScreenRect.top
  383.  
  384.             amountOffscreen = perfectWindowRect.bottom - bestScreenRect.bottom;
  385.             if (amountOffscreen > 0)
  386.             {
  387.                 //    Are we going to push the top edge offscreen? If so, change the
  388.                 //    offset so we move the window just to the top.
  389.                 
  390.                 if ((perfectWindowRect.top - amountOffscreen) < bestScreenRect.top)
  391.                     amountOffscreen = perfectWindowRect.top - bestScreenRect.top;
  392.  
  393.                 perfectWindowRect.top -= amountOffscreen;
  394.                 perfectWindowRect.bottom -= amountOffscreen;
  395.             }
  396.  
  397.             SectRect(&perfectWindowRect, &bestScreenRect, &scratchRect);
  398.             if (!EqualRect(&perfectWindowRect, &scratchRect))
  399.             {
  400.                 //    The edges of the window still fall offscreen,
  401.                 //    so make the window smaller until it fits.
  402.                 
  403.                 if (perfectWindowRect.bottom > bestScreenRect.bottom)
  404.                     perfectWindowRect.bottom = bestScreenRect.bottom;
  405.  
  406.                 //    If the right edge is still falling off,
  407.                 //        save space for Finder’s disk icons as well.
  408.  
  409.                 if (perfectWindowRect.right > bestScreenRect.right)
  410.                 {
  411.                     perfectWindowRect.right = bestScreenRect.right;
  412.                     
  413.                     //    If we were on the main screen, leave room for Finder icons, too.
  414.                     
  415.                     if (bestDevice == GetMainDevice())
  416.                         perfectWindowRect.right -= kSpaceForFinderIcons;
  417.                 }
  418.             }
  419.         }
  420.  
  421.         //    Stash our new rectangle inside of the Window’s dataHandle
  422.         //    so that ZoomWindow does the right thing.
  423.         
  424.         (**((WStateDataHandle) (windowAsWindowPeek->dataHandle))).stdState = perfectWindowRect;
  425.     }
  426.  
  427.     //    HEY YOU! Don’t forget to set the port to the window being zoomed
  428.     //    Why, you ask? Because IM-IV-50 says to; otherwise you die
  429.     
  430.     SetPort(fWindow);
  431.  
  432.     Rect    oldWindowRect = fWindow->portRect;
  433.     
  434.     ZoomWindow(fWindow,zoomState,false);
  435.     this->AdjustForNewWindowSize(&oldWindowRect,&fWindow->portRect);
  436. }
  437.  
  438. void TWindow::ShowHide(Boolean showFlag)
  439. {
  440.     //    Here we need the “::” in front of ShowHide to indicate we are calling
  441.     //    the global function, and not the method ShowHide. Unintended recursion
  442.     //    can do bad things to the unsuspecting programmer.
  443.     
  444.     //    Some C++ programmers would always prepend the “::” on function calls.
  445.     
  446.     ::ShowHide(fWindow,showFlag);
  447.     fIsVisible = showFlag;
  448. }
  449.     
  450. Boolean TWindow::EventFilter(EventRecord * /* theEvent */)
  451. {
  452.     return false;
  453. }
  454.     
  455. void TWindow::GetPerfectWindowSize(Rect *pPerfectSize)
  456. {
  457.     *pPerfectSize = qd.screenBits.bounds;
  458. }
  459.  
  460. void TWindow::GetWindowSizeLimits(Rect *limits)
  461. {
  462.     limits->top = limits->left = kMinimumWindowSize;
  463.     limits->right = gDeskRectangle.right - gDeskRectangle.left;
  464.     limits->bottom = gDeskRectangle.bottom - gDeskRectangle.top;
  465. }
  466.  
  467. void TWindow::AdjustForNewWindowSize(Rect * /* oldRect */, Rect * /* newSize */)
  468. {
  469. }
  470.  
  471. Boolean TWindow::IsVisible(void)
  472. {
  473.     return fIsVisible;
  474. }
  475.  
  476. Boolean TWindow::CanClose(void)
  477. {
  478.     return true;
  479. }
  480.  
  481. Boolean TWindow::Close(void)
  482. {
  483.     WindowPtr    newFrontWindow = nil;
  484.     
  485.     if (FrontNonFloatingWindow() == fWindow)
  486.         newFrontWindow = (WindowPtr) ((WindowPeek) fWindow)->nextWindow;
  487.  
  488.     this->Activate(false);
  489.     DisposeWindow(fWindow);
  490.  
  491.     if (newFrontWindow)
  492.         HiliteAndActivateWindow(newFrontWindow,true);
  493.  
  494.     return true;
  495. }
  496.  
  497. Boolean TWindow::DeleteAfterClose(void)
  498. {
  499.     return true;
  500. }
  501.  
  502. void TWindow::DoEditMenu(short /* menuCode */)
  503. {
  504. }
  505.  
  506. void  TWindow::HandleMenuCommand(short theMenuID, short theMenuItem)
  507. {
  508.     switch(theMenuID)
  509.     {
  510.         case mFile :
  511.             switch(theMenuItem)
  512.             {
  513.                 case    iPageSetup:                    PageSetupDlg(false);        break;
  514.                 case    iCustomPageSetup:        PageSetupDlg(true);        break;
  515.                 case    iPrint:                            PrintDlg(true);                break;
  516.                 case    iPrintOneCopy:                PrintDlg(false);                break;
  517.             }
  518.             break;
  519.         default :
  520.             break;
  521.     }
  522.     // this top level of virtual
  523. }
  524.  
  525. void TWindow::PageSetupDlg(Boolean /*theCustomFlag*/)
  526. {
  527. }
  528.  
  529. void TWindow::PrintDlg(Boolean /*theDialogFlag*/)
  530. {
  531. }
  532.  
  533. OSErr TWindow::HandleDrag(DragTrackingMessage dragMessage,DragReference theDrag)
  534. {
  535.     OSErr    result = dragNotAcceptedErr;
  536.     
  537.     switch (dragMessage)
  538.     {
  539.         case    dragTrackingEnterWindow:
  540.             result = this->DragEnterWindow(theDrag);
  541.             break;
  542.         
  543.         case    dragTrackingInWindow:
  544.             result = this->DragInWindow(theDrag);
  545.             break;
  546.             
  547.         case    dragTrackingLeaveWindow:
  548.             result = this->DragLeaveWindow(theDrag);
  549.             break;
  550.             
  551.         default:
  552.             break;
  553.     }
  554.  
  555.     return result;
  556. }
  557.  
  558. OSErr TWindow::DragEnterWindow(DragReference /* theDrag */)
  559. {
  560.     return dragNotAcceptedErr;
  561. }
  562.  
  563. OSErr TWindow::DragInWindow(DragReference /* theDrag */)
  564. {
  565.     return dragNotAcceptedErr;
  566. }
  567.  
  568. OSErr TWindow::DragLeaveWindow(DragReference /* theDrag */)
  569. {
  570.     return dragNotAcceptedErr;
  571. }
  572.     
  573. OSErr TWindow::HandleDrop(DragReference /* theDrag */)
  574. {
  575.     return dragNotAcceptedErr;
  576. }
  577.  
  578. ///////////////////////////////////////////////////////////////////////////
  579. //
  580. //    Utility Functions used for floating windows
  581. //
  582. TWindow* GetWindowObject(WindowPtr aWindow)
  583. {
  584.     short    wKind;
  585.     
  586.     if (aWindow != nil)
  587.     {
  588.         wKind = ((WindowPeek) aWindow)->windowKind;
  589.  
  590.         if (wKind >= userKind)
  591.         {
  592.             //    All windowKinds >= userKind are based upon TWindow
  593.             return (TWindow *) GetWRefCon(aWindow);
  594.         }
  595.     }
  596.     return  nil;
  597. }
  598.  
  599.  
  600. ////////////////////////////////////////////////////////////////////////
  601. //
  602. //    Utility functions
  603. pascal WindowPtr GetNewColorOrBlackAndWhiteWindow(short windowID, void *wStorage, WindowPtr behind)
  604. {
  605.     if (gHasColorQuickdraw)
  606.         return GetNewCWindow(windowID,wStorage,behind);
  607.     else
  608.         return GetNewWindow(windowID,wStorage,behind);
  609. }
  610.  
  611. pascal WindowPtr NewColorOrBlackAndWhiteWindow(void *wStorage, const Rect *boundsRect, ConstStr255Param title, Boolean visible, short theProc, WindowPtr behind, Boolean goAwayFlag, long refCon)
  612. {
  613.     if (gHasColorQuickdraw)
  614.         return NewCWindow(wStorage,boundsRect,title,visible,theProc,behind,goAwayFlag,refCon);
  615.     else
  616.         return NewWindow(wStorage,boundsRect,title,visible,theProc,behind,goAwayFlag,refCon);
  617. }
  618.  
  619. WindowPtr LastFloatingWindow(void)
  620. {
  621.     WindowPeek    aWindow = (WindowPeek) FrontWindow();
  622.     WindowPtr    lastFloater = (WindowPtr) kNoFloatingWindows;
  623.     
  624.     while (aWindow && (aWindow->windowKind == kFloatingWindowKind))
  625.     {
  626.         if (aWindow->visible)
  627.             lastFloater = (WindowPtr) aWindow;
  628.  
  629.         aWindow = (WindowPeek) aWindow->nextWindow;
  630.     }
  631.     return(lastFloater);
  632. }
  633.  
  634. WindowPtr FrontNonFloatingWindow(void)
  635. {
  636.     WindowPeek    aWindow = (WindowPeek) LMGetWindowList();
  637.  
  638.     //    Skip over floating windows
  639.         
  640.     while (aWindow && (aWindow->windowKind == kFloatingWindowKind))
  641.         aWindow = (WindowPeek) aWindow->nextWindow;
  642.  
  643.     //    Skip over invisible, but otherwise normal windows
  644.     
  645.     while (aWindow && (aWindow->visible == 0))
  646.         aWindow = (WindowPeek) aWindow->nextWindow;
  647.         
  648.     return (WindowPtr) aWindow;
  649. }
  650.  
  651. void HiliteAndActivateWindow(WindowPtr aWindow,Boolean active)
  652. {
  653.     TWindow    *    wobj = GetWindowObject(aWindow);
  654.     
  655.     if (aWindow)
  656.     {
  657.         HiliteWindow(aWindow,active);
  658.  
  659.         if (wobj != nil)
  660.         {
  661.             CSavePort  aSavePort(aWindow);
  662.             wobj->Activate(active);
  663.         }    
  664.     }
  665. }
  666.  
  667. void SuspendResumeWindows(Boolean resuming)
  668. {
  669.     //    When we suspend/resume, hide/show all the visible floaters
  670.     HiliteShowHideFloatingWindows(resuming,true);
  671. }
  672.  
  673. void HiliteWindowsForModalDialog(Boolean hiliting)
  674. {
  675.     //    When we display a modal dialog, we need to unhighlight
  676.     //    all visible floaters. We also need to re-hilite them
  677.     //    afterwards.
  678.     HiliteShowHideFloatingWindows(hiliting,false);
  679. }
  680.  
  681. void HiliteShowHideFloatingWindows(Boolean hiliting,Boolean dohiding)
  682. {
  683.     WindowPeek    aWindow;
  684.     TWindow *    wobj;
  685.     
  686.     HiliteAndActivateWindow(FrontNonFloatingWindow(),hiliting);
  687.  
  688.     aWindow = LMGetWindowList();
  689.     while (aWindow && aWindow->windowKind == kFloatingWindowKind)
  690.     {
  691.         wobj = GetWindowObject((WindowPtr) aWindow);
  692.         
  693.         //    If we are hiding or showing, only hide/show windows
  694.         //    that were visible to begin with.
  695.         
  696.         //    NOTE:    We use our copy of the visible flag so we can
  697.         //            automatically show floaters on a resume event.
  698.         
  699.         //    NOTE:    Since this isn’t a method of TWindow, we don’t
  700.         //            really need the “::” on ShowHide, but as long
  701.         //            as we’re trying to avoid ambiguity.
  702.         
  703.         if (dohiding && (wobj != nil) && (wobj->IsVisible()))
  704.             ::ShowHide((WindowPtr) aWindow,hiliting);
  705.             
  706.         //    All floaters are hilited if any floater is hilited
  707.  
  708.         HiliteWindow((WindowPtr) aWindow,hiliting);
  709.         aWindow = (WindowPeek) aWindow->nextWindow;
  710.     }
  711. }
  712.  
  713. ///////////////////////////////////////////////////////////////////////////
  714. //
  715. //    Routines used for dealing with windows and multiple screens
  716. //
  717.  
  718. pascal void CalculateWindowAreaOnDevice(short /* depth */,short /* deviceFlags */,GDHandle targetDevice,long userData)
  719. {
  720.     CalcWindowAreaDeviceLoopUserData *    deviceLoopDataPtr;
  721.     long                                windowAreaOnThisScreen;
  722.     Rect                                windowRectOnThisScreen;
  723.     
  724.     deviceLoopDataPtr = (CalcWindowAreaDeviceLoopUserData *) userData;
  725.  
  726.     SectRect(&deviceLoopDataPtr->fWindowBounds, &(**targetDevice).gdRect,&windowRectOnThisScreen);
  727.     OffsetRect(&windowRectOnThisScreen,-windowRectOnThisScreen.left,-windowRectOnThisScreen.top);
  728.     windowAreaOnThisScreen = windowRectOnThisScreen.right * windowRectOnThisScreen.bottom;
  729.  
  730.     if (windowAreaOnThisScreen > deviceLoopDataPtr->fLargestArea)
  731.     {
  732.         deviceLoopDataPtr->fLargestArea = windowAreaOnThisScreen;
  733.         deviceLoopDataPtr->fScreenWithLargestPartOfWindow = targetDevice;
  734.     }
  735. }
  736.  
  737. DeviceLoopDrawingUPP CallCalcWindowAreaOnDevice = NewDeviceLoopDrawingProc(&CalculateWindowAreaOnDevice);
  738.  
  739. void FindScreenRectWithLargestPartOfWindow(WindowPtr aWindow,Rect *theBestScreenRect,GDHandle * theBestDevice)
  740. {
  741.     RgnHandle                            copyOfWindowStrucRgn;
  742.     CalcWindowAreaDeviceLoopUserData    deviceLoopData;
  743.  
  744.     //    Use DeviceLoop to find out what GDevice contains the largest
  745.     //    portion of the supplied window.
  746.     //
  747.     //    NOTE:    Assumes thePort == the Window Manager Port because we using
  748.     //            the window strucRgn, not contRgn.
  749.  
  750.     deviceLoopData.fScreenWithLargestPartOfWindow = nil;
  751.     deviceLoopData.fLargestArea = -1;
  752.     deviceLoopData.fWindowBounds = (**(((WindowPeek) aWindow)->contRgn)).rgnBBox;
  753.     
  754.     copyOfWindowStrucRgn = NewRgn();
  755.     CopyRgn(((WindowPeek) aWindow)->strucRgn,copyOfWindowStrucRgn);
  756.  
  757.     DeviceLoop(copyOfWindowStrucRgn,CallCalcWindowAreaOnDevice,(long) &deviceLoopData,singleDevices);    
  758.  
  759.     DisposeRgn(copyOfWindowStrucRgn);
  760.     
  761.     *theBestDevice = deviceLoopData.fScreenWithLargestPartOfWindow;
  762.     *theBestScreenRect = (**(deviceLoopData.fScreenWithLargestPartOfWindow)).gdRect;
  763.  
  764.     //    Leave some space around the edges of the screen so window look good, AND
  765.     //    if the best device is the main screen, leave space for the Menubar
  766.     
  767.     InsetRect(theBestScreenRect,kScreenEdgeSlop,kScreenEdgeSlop);
  768.     if (GetMainDevice() == deviceLoopData.fScreenWithLargestPartOfWindow)
  769.         theBestScreenRect->top += GetMBarHeight();
  770. }
  771.  
  772. ///////////////////////////////////////////////////////////////////////////
  773. //
  774. //    Drag Manager callback routines which dispatch to a window’s method
  775. //
  776. pascal OSErr CallWindowDragTrackingHandler(DragTrackingMessage dragMessage,WindowPtr theWindow,void * /* refCon */,DragReference theDrag)
  777. {
  778.     TWindow *wobj = GetWindowObject(theWindow);
  779.     
  780.     if (wobj)
  781.         return(wobj->HandleDrag(dragMessage,theDrag));
  782.     else
  783.         return dragNotAcceptedErr;
  784. }
  785.     
  786. pascal OSErr CallWindowDragReceiveHandler(WindowPtr theWindow,void * /* refCon */,DragReference theDrag)
  787. {
  788.     TWindow *wobj = GetWindowObject(theWindow);
  789.     
  790.     if (wobj)
  791.         return(wobj->HandleDrop(theDrag));
  792.     else
  793.         return dragNotAcceptedErr;
  794. }
  795.